package transaction.lcn.account.service;

import com.yiqiniu.easytrans.core.EasyTransFacade;
import com.yiqiniu.easytrans.protocol.BusinessProvider;
import com.yiqiniu.easytrans.protocol.tcc.EtTcc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;
import transaction.lcn.account.mapper.AccountTblMapper;
import transaction.lcn.account.model.AccountTbl;
import transaction.lcn.common.tcc.WalletPayRequestVO;
import transaction.lcn.common.tcc.WalletPayResponseVO;
import transaction.lcn.common.tcc.requestcfg.WalletPayRequestCfg;

import javax.annotation.Resource;
import java.util.List;

@Service
@Slf4j
public class AccountService {

    private static final String ERROR_USER_ID = "1002";
    @Resource
    private EasyTransFacade transaction;
    @Autowired
    private AccountTblMapper accountMapper;

    //    @LcnTransaction //分布式事务注解
//    @Transactional(rollbackFor = Exception.class) //本地事务注解
    public void debit(String userId, Integer num) {

        AccountTbl account = selectByUserId(userId);
        assert account != null;
        int row = accountMapper.updateByPrimaryKeySelectiveNew(account.getId(), num);
        if (row < 1) {
            log.error("账户钱不够了 {},{}", userId, account.getMoney());
            throw new RuntimeException("账户钱不够了" + userId + ":" + account.getMoney());
        }

        if (ERROR_USER_ID.equals(userId)) {
            throw new RuntimeException("account branch exception");
        }
    }

    private AccountTbl selectByUserId(String userId) {
        Example example = new Example(AccountTbl.class);
        example.createCriteria().andEqualTo("userId", userId);
        List<AccountTbl> list = accountMapper.selectByExample(example);
        return CollectionUtils.isEmpty(list) ? null : list.get(0);
    }


    //如果doTryPay的入参为集成了EasyTransRequest并带有BusinessIdentiffer的话则无需指定cfgClass
    @Transactional
    @EtTcc(confirmMethod = "doConfirmPay", cancelMethod = "doCancelPay", idempotentType = BusinessProvider.IDENPOTENT_TYPE_FRAMEWORK, cfgClass = WalletPayRequestCfg.class)
    public WalletPayResponseVO doTryPay(WalletPayRequestVO param) {
//        int update = jdbcTemplate.update("update `wallet` set freeze_amount = freeze_amount + ? where user_id = ? and (total_amount - freeze_amount) >= ?;",
//                param.getPayAmount(),param.getUserId(),param.getPayAmount());
//
//        if(update != 1){
//            throw new RuntimeException("can not find specific user id or have not enought money");
//        }
        Assert.notNull(param.getUserId());
        Assert.notNull(param.getUserId());
        int row = accountMapper.doTryPay(param);
        if (row < 1) {
            log.error("账户钱不够了 {},{}", param.getUserId(), param.getPayAmount());
            throw new RuntimeException("账户钱不够了" + param.getUserId() + ":" + param.getPayAmount());
        }
        WalletPayResponseVO walletPayTccMethodResult = new WalletPayResponseVO();
        walletPayTccMethodResult.setFreezeAmount(param.getPayAmount());
        return walletPayTccMethodResult;
    }


    @Transactional
    public void doConfirmPay(WalletPayRequestVO param) {
//        int update = jdbcTemplate.update("update `wallet` set freeze_amount = freeze_amount - ?, total_amount = total_amount - ? where user_id = ?;",
//                param.getPayAmount(),param.getPayAmount(),param.getUserId());
        int update = accountMapper.doConfirmPay(param);
        if (update != 1) {
            throw new RuntimeException("unknow Exception!");
        }
    }

    @Transactional
    public void doCancelPay(WalletPayRequestVO param) {
//        int update = jdbcTemplate.update("update `wallet` set freeze_amount = freeze_amount - ? where user_id = ?;",
//                param.getPayAmount(),param.getUserId());
        int update = accountMapper.doCancelPay(param);
        if (update != 1) {
            throw new RuntimeException("unknow Exception!");
        }
    }


}
